/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.felix.ipojo.extender;

import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
import org.apache.felix.ipojo.metadata.Element;

/**
 * This service provides a way for users to manage declarations through code.
 *
 * Notice that produced declarations are immutable once build. But it is possible to re-use a
 * builder to share some configuration through instances.
 *
 * <pre>
 *     // Obtain the service through the service registry
 *     DeclarationBuilderService service = ...
 *
 *     // Get a fresh instance builder
 *     DeclarationBuilder builder = service.newInstance("the.full.name.of.the.component.to.instantiate");
 *
 *     DeclarationHandle handle = builder.name("a-unique-name") // Make sure name is unique for the expected type
 *                                       .configure()
 *                                           .property("a-property", "a-value")
 *                                           .property("another-property", "another-value")
 *                                           .build();
 *
 *     // Push the InstanceDeclaration service in the registry
 *     handle.publish();
 * </pre>
 *
 * Except the {@link InstanceBuilder#build()} call, all methods are optional:
 * <ul>
 *     <li>{@link InstanceBuilder#name(String)}: if no name is provided,
 *     a default one will be generated by iPOJO.</li>
 *     <li>{@link InstanceBuilder#version(String)}: if no version is provided,
 *     the first un-versioned type will be used.</li>
 *     <li>{@link InstanceBuilder#configure()}: if no configuration is required, can be omitted.</li>
 *     <li>{@link InstanceBuilder#type(String)}: can be used to change the <bold>required</bold> component type.</li>
 *     <li>{@link InstanceBuilder#context(org.osgi.framework.BundleContext)}: by default, the bundle context
 *     used to register the created {@link org.apache.felix.ipojo.extender.Declaration} is the one of the
 *     caller. It can be changed though this method.</li>
 * </ul>
 *
 * Once an instance handle has been created, its configuration (name, type, version and properties) is immutable. It can
 * only be {@linkplain DeclarationHandle#publish() published} (so that the framework will try to instantiate the
 * instance) or {@linkplain DeclarationHandle#retract() retracted} (framework will remove the instance).
 *
 * Notice that all created instances will appear as "coming from" the bundle that requires the
 * {@link DeclarationBuilderService} service. Just like having a {@literal metadata.xml} file in your
 * bundle that declares your instances. It is possible to override this default behavior using
 * {@link InstanceBuilder#context(org.osgi.framework.BundleContext)}.
 *
 * @see org.apache.felix.ipojo.extender.InstanceDeclaration
 * @see org.apache.felix.ipojo.extender.TypeDeclaration
 * @see org.apache.felix.ipojo.extender.ExtensionDeclaration
 * @see org.apache.felix.ipojo.extender.InstanceBuilder
 * @see org.apache.felix.ipojo.extender.ConfigurationBuilder
 * @see org.apache.felix.ipojo.extender.DeclarationHandle
 *
 * @since 1.11.2
 */
public interface DeclarationBuilderService {

    /**
     * Declares a new anonymous instance of a given type.
     * Invoking this method is equivalent to invoking <code>{@linkplain #newInstance(String, String) newInstance(type, null)}</code>.
     * @param type name of the component to be instantiated (cannot be null).
     * @return a handle usable to publish / retract the declaration.
     * @see org.apache.felix.ipojo.extender.InstanceDeclaration
     */
    InstanceBuilder newInstance(String type);

    /**
     * Declares a new instance of a given type.
     * Invoking this method is equivalent to invoking <code>{@linkplain #newInstance(String, String, String) newInstance(type, name, null)}</code>.
     * @param type name of the component to be instantiated.
     * @param name name of the new instance (can be null)
     * @return a handle usable to publish / retract the declaration.
     * @see org.apache.felix.ipojo.extender.InstanceDeclaration
     */
    InstanceBuilder newInstance(String type, String name);

    /**
     * Declares a new instance of a given type.
     * @param type name of the component to be instantiated.
     * @param name name of the new instance (can be null)
     * @param version version of the expected type (can be null)
     * @return a handle usable to publish / retract the declaration.
     * @see org.apache.felix.ipojo.extender.InstanceDeclaration
     */
    InstanceBuilder newInstance(String type, String name, String version);

    /**
     * Declares a new extension (supports new types like {@literal component}, {@literal composite}, {@literal handler}).
     * @param name name of the type to support (no namespace to be provided)
     * @param builder associated factory builder
     * @return a handle usable to publish / retract the declaration.
     * @see org.apache.felix.ipojo.IPojoFactory
     * @see org.apache.felix.ipojo.extender.ExtensionDeclaration
     */
    DeclarationHandle newExtension(String name, FactoryBuilder builder);

    /**
     * Declares a new type using the given element description.
     * @param description description of the component type
     * @return a handle usable to publish / retract the declaration.
     * @see org.apache.felix.ipojo.extender.TypeDeclaration
     */
    DeclarationHandle newType(Element description);
}
